
package cn.tang.tframe.dynconfig.lock;

import cn.tang.tframe.client.zookeeper.ZKClient;
import cn.tang.tframe.common.base.MainConfigLoader;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.apache.curator.framework.recipes.locks.InterProcessReadWriteLock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;

/**
 * Created by tanghc on 17/1/23.
 */
public class ZkLock {

	static final Logger logger = LoggerFactory.getLogger(ZkLock.class);
	private static ConcurrentMap<String, InterProcessReadWriteLock> locks =
		new ConcurrentHashMap<>();

	private ZkLock() {
	}

	private static class RedisLockHolder {

		private static ZkLock instance = new ZkLock();
	}

	public static ZkLock getInstance() {

		return RedisLockHolder.instance;
	}

	/**
	 * redis全局锁,一次获取不到等待1ms继续获取,最长等待maxWaitMs
	 * 
	 * @param lock
	 *            锁标示
	 * @param maxWaitMs
	 *            获取锁最长等待的时间,毫秒,超过这个时间则获取锁失败
	 * @return
	 */
	public boolean acquireLock(final String lock, final long maxWaitMs) {

		logger.debug(
			"acquireLock start:[lock={}][maxWaitMs={}]", lock, maxWaitMs);
		InterProcessMutex wLock = getWLock(lock);
		if (null == wLock) {
			return false;
		}
		logger.debug(
				"acquireLock start:[wLock={}]]", wLock);
		try {
			return wLock.acquire(maxWaitMs, TimeUnit.MILLISECONDS);
		}
		catch (Exception e) {
			logger.error("获取锁资源出现异常|lockKey:[{}]", lock, e);
		}
		return false;
	}

	/**
	 * 解锁
	 */
	public void releaseLock(final String lock)
		throws Exception {

		logger.debug("releaseLock start:[lock={}]", lock);
		InterProcessMutex wLock = getWLock(lock);
		if (null == wLock) {
			throw new RuntimeException(
				"release zk lock exception without lock");
		}
		wLock.release();
	}

	private InterProcessReadWriteLock getWRLock(String key) {

		String lockPath = getLockPath(key);
		InterProcessReadWriteLock interProcessReadWriteLock =
			locks.get(lockPath);
		if (null == interProcessReadWriteLock) {
			CuratorFramework client = ZKClient.getClient();
			System.out.println("############"+client);
			interProcessReadWriteLock =
				new InterProcessReadWriteLock(client, lockPath);
			locks.putIfAbsent(lockPath, interProcessReadWriteLock);
			interProcessReadWriteLock = locks.get(lockPath);// 保证是统一个锁
		}
		return interProcessReadWriteLock;
	}

	private InterProcessMutex getWLock(String key) {

		InterProcessReadWriteLock interProcessReadWriteLock = getWRLock(key);
		if (null != interProcessReadWriteLock) {
			return interProcessReadWriteLock.writeLock();
		}
		return null;
	}

	private InterProcessMutex getRLock(String key) {

		InterProcessReadWriteLock interProcessReadWriteLock = getWRLock(key);
		if (null != interProcessReadWriteLock) {
			return interProcessReadWriteLock.readLock();
		}
		return null;
	}

	private String getLockPath(String key) {

		return new StringBuilder().append("/biz/lock/").append(
			MainConfigLoader.getInstance().getProductCode()).append(
				"/").append(
					MainConfigLoader.getInstance().getAppCode()).append(
						"/").append(key).toString();
	}
}
